/**
 * (c) 2015-2020
 * Author: zeyuphoenix
 * License: www.blogjava.net/zeyuphoenix
 * version: 1.0.0
 */
(function (root, factory) {

    "user strict";

    if (typeof define === 'function' && define.amd) {
        define(['jquery', 'zTree'], factory);
    } else {
        root.TreeSelecter = factory($, jQuery.fn.zTree);
    }
}(this, function ($, zTree) {

    "user strict";

    // 提供项目的默认配置项,保持风格统一,覆盖配置项
    var defaultOptions = {
        // dom 节点
        databind: null,
        // 对话框弹出对话框需要外部定义一个div
        databind_dialog: null,
        // 选择框标题
        title: '',
        // 编号,为了排重，加入了随机数
        id: '',
        // 隐藏域名称 -- 提交name（表单input）
        name: '',
        // 隐藏域值 -- 提交value
        value: '',
        // 输入框名称 -- 显示框name
        labelName: '',
        // 输入框值
        labelValue: '',
        // 数据请求url地址,树结构数据地址
        dataurl: '',
        // 数据请求参数
        // 排除掉的编号(不能选择的编号)，id在id（子id）下可能会有问题 --> extId 参数一般会有
        params: {},
        // 自定义数据
        attach: '',

        // 非必需参数
        // 是否显示复选框
        checked: true,
        // 选择框类型 checkbox / radio
        chkStyle: 'radio',
        // 确定的回调函数
        callback: null,
        // 是否列出全部数据，设置true则不进行数据权限过滤
        isAll: true,
        // 不允许选择根节点
        notAllowSelectRoot: false,
        // 不允许选择父节点
        notAllowSelectParent: false,
        // 过滤栏目模型(只显示指定模型)
        module: '',
        // 选择范围内的模型(控制不能选择公共模型，不能选择本栏目外的模型)
        selectScopeModule: false,
        // 是否允许清除
        allowClear: true,
        // 文本框可填写
        allowInput: false,
        // css样式
        cssClass: '',
        // css样式
        cssStyle: '',
        // 缩小按钮显示
        smallBtn: false,
        // 隐藏按钮
        hideBtn: false,
        // 是否限制选择，如果限制，设置为disabled
        disabled: '',
        // 标签属性
        dataMsgRequired: '',
        // 树选择框类型
        chkboxType: {'Y': 'ps', 'N': 'ps'}
    };

    // 树选择框对象,创建的唯一入口
    var TreeSelecter = function (options) {
        this.options = $.extend(true, {}, defaultOptions, options);
        if (this.options.id == null || this.options.id == '') {
            this.options.id = 'id_' + Math.round(Math.random() * 10000);
        }
        this.__init();
    };

    // 树选择框的配置
    // 树选择框的对象方法
    TreeSelecter.prototype = {

        // 构造
        constructor: TreeSelecter,

        // 获取默认的常量

        // 初始化
        __init: function () {
            var self = this;
            // 取得默认配置

            //创建表格HTML
            this.$element = $(this.options.databind);
            this.$element.html(this.createTemplate());

            // 对话框的html暂时不显示
            var $layer = $("#" + self.options.id + "Tree").closest('.layer-dialog');
            $layer.hide();

            //注册事件
            this.registerEvent();

            var key = $layer.find('#' + this.options.id + 'key');
            this.options.key = key;

            key.bind("focus", function () {
                if (self.options.key.hasClass("empty")) {
                    self.options.key.removeClass("empty");
                }
            });
            key.bind("blur", function () {
                if (self.options.key.get(0).value === "") {
                    self.options.key.addClass("empty");
                }
                self.searchNode();
            });
            key.bind("change cut input propertychange", function () {
                self.searchNode();
            });
            key.bind('keydown', function (e) {
                if (e.which == 13) {
                    self.searchNode();
                }
            });

            // action
            $layer.find('#' + this.options.id + 'showSearch').on('click', function () {
                self.search();
            });
            $layer.find('#' + this.options.id + 'btn').on('click', function () {
                self.searchNode();
            });
        },

        /**
         * 因为不能每次都初始化，也不能使用模板，所以需要改变输入内容时调用这个方法
         */
        refresh: function (options) {
            // 覆盖自己输入属性
            this.options = $.extend(true, {}, this.options, options);
            // id、name 固定
            // 设置value
            $("#" + this.options.id + "Id").val(this.options.value);
            // 设置labelValue
            $("#" + this.options.id + "Name").val(this.options.labelValue.replace(/^<i.+><\/i>/ig, ""));
        },

        /**
         * 创建表单html内容
         */
        createTemplate: function () {
            // 加入参数，注意key重复
            var formTemplate = ''
                + ' <div class="input-group form-tree-info">'
                + '     <input id="' + this.options.id + 'Id" name="' + this.options.name + '" class="' + this.options.cssClass + '"'
                + '         type="hidden" value="' + this.options.value + '"/>'
                + '     <input id="' + this.options.id + 'Name" name="' + this.options.labelName + '" ' + (this.options.allowInput ? '' : 'readonly = "readonly"') + ' type="text"'
                + '         value="' + this.options.labelValue + '" data-msg-required="' + this.options.dataMsgRequired + '"'
                + '         class="form-control ' + this.options.cssClass + '"/>'
                + '     <span class="input-group-addon">'
                + '         <a id="' + this.options.id + 'Button" href="javascript:" '
                + '             class="' + this.options.disabled + (this.options.hideBtn ? ' hide' : '') + '">'
                + '             <i class="fa fa-search txt-color-green"></i>'
                + '         </a>'
                + '     </span>'
                + ' </div>';
            var treeTemplate = ''
                + ' <section class="layer-dialog">'
                + '     <div class="container-fluid">'
                + '     <div class="row">'
                + '         <div class="col-sm-12 col-md-12 col-lg-12" style="padding:0">'
                + '             <div id="' + this.options.id + 'showSearch" style="position:absolute;right:12px;top:12px;cursor:pointer;">'
                + '                 <i class="fa fa-search"></i><label id="' + this.options.id + 'txt" class="txt-color-green">搜索</label>'
                + '             </div>'
                + '             <div id="' + this.options.id + 'search" class="" style="padding:8px 0 0 2px;display: none;">'
                + '                 <label for="' + this.options.id + 'key" class="control-label" style="padding:0 5px 0px 25px;">关键字：</label>'
                + '                 <input type="text" class="empty" id="' + this.options.id + 'key" name="key" style="width:170px;">'
                + '                 <button class="btn btn-info" style="display: none;" id="' + this.options.id + 'btn">搜索</button>'
                + '             </div>'
                + '             <div id="' + this.options.id + 'Tree" class="ztree" style="padding:12px 10px 2px 10px;"></div>'
                + '         </div>'
                + '     </div>'
                + '     </div>'
                + ' </section>';
            if (this.options.databind_dialog != null) {
                $(this.options.databind_dialog).html(treeTemplate);
                return formTemplate;
            }
            return formTemplate + treeTemplate;
        },

        /**
         * 注册输入框、按钮的事件
         */
        registerEvent: function () {
            var self = this;
            // 需要注册事件的组件
            $('#' + this.options.id + 'Button, #' + this.options.id + 'Name').on('click', function () {
                // 是否限制选择，如果限制，设置为disabled
                if ($('#' + self.options.id + 'Button').hasClass("disabled")) {
                    return true;
                }
                self.request();
                self.treeLayer();
            });
        },

        /**
         * 弹出tree选择对话框1
         */
        treeLayer: function () {
            var self = this;
            // 显示的按钮
            var btn = [];
            if (this.options.allowClear == true || this.options.allowClear == "true") {
                btn = ['确定', '清除', '关闭'];
            } else {
                btn = ['确定', '关闭'];
            }
            var $layer = $("#" + self.options.id + "Tree").closest('.layer-dialog');

            // 正常打开
            window.top.layer.open({
                type: 1,
                title: '选择' + self.options.title,
                shadeClose: true,
                shade: false,
                maxmin: true, //开启最大化最小化按钮
                area: ['300px', '480px'],
                content: $layer,
                success: function (layero) {
                },
                btn: btn,
                yes: function (index) { //或者使用btn1
                    // 按钮【确定】的回调
                    // 获取tree
                    var tree = $.fn.zTree.getZTreeObj(self.options.id + "Tree");
                    var ids = [], names = [], nodes = [];

                    // 获取选择节点
                    if (self.options.checked == true) {
                        nodes = tree.getCheckedNodes(true);
                    } else {
                        nodes = tree.getSelectedNodes();
                    }
                    var has = false;
                    for (var i = 0; i < nodes.length; i++) {
                        if (self.options.checked && self.options.notAllowSelectParent) {
                            if (nodes[i].isParent) {
                                if (i == nodes.length - 1 && !has) {
                                    // 不允许选中父节点,但是子节点页没有选
                                    window.top.layer.msg("不能选择父节点（" + nodes[i].name + "）请重新选择。", {
                                        icon: 5,
                                        time: 2000 //2秒关闭（如果不配置，默认是3秒）
                                    });
                                    return false;
                                }
                                continue; // 如果为复选框选择，则过滤掉父节点
                            }
                        }
                        if (self.options.notAllowSelectRoot) {
                            if (nodes[i].level == 0) {
                                window.top.layer.msg("不能选择根节点（" + nodes[i].name + "）请重新选择。", {
                                    icon: 5,
                                    time: 2000 //2秒关闭（如果不配置，默认是3秒）
                                });
                                return false;
                            }
                        }
                        if (self.options.notAllowSelectParent) {
                            if (nodes[i].isParent) {
                                window.top.layer.msg("不能选择父节点（" + nodes[i].name + "）请重新选择。", {
                                    icon: 5,
                                    time: 2000 //2秒关闭（如果不配置，默认是3秒）
                                });
                                return false;
                            }
                        }
                        if (self.options.selectScopeModule && self.options.module != null && self.options.module != '') {
                            if (nodes[i].module == "") {
                                window.top.layer.msg("不能选择公共模型（" + nodes[i].name + "）请重新选择。", {
                                    icon: 5,
                                    time: 2000 //2秒关闭（如果不配置，默认是3秒）
                                });
                                return false;
                            } else if (nodes[i].module != self.options.module) {
                                window.top.layer.msg("不能选择当前栏目以外的栏目模型，请重新选择。", {
                                    icon: 5,
                                    time: 2000 //2秒关闭（如果不配置，默认是3秒）
                                });
                                return false;
                            }
                        }
                        has = true;
                        ids.push(nodes[i].id);
                        names.push(nodes[i].name);
                        if (!self.options.checked) {
                            break; // 如果为非复选框选择，则返回第一个选择
                        }
                    }
                    var $idv = $("#" + self.options.id + "Id");
                    $idv.val(ids.join(",").replace(/u_/ig, ""));
                    $("#" + self.options.id + "Name").val(names.join(",").replace(/^<i.+><\/i>/ig, ""));

                    if (self.options.callback && (typeof self.options.callback == 'function')) {
                        self.options.callback.call(this, $idv.val(), self.options.dataself);
                    }

                    // 默认关闭事件
                    layer.close(index);
                },
                btn2: function (index) { //或者使用btn2
                    //按钮【清除】的回调
                    if (self.options.allowClear == true || self.options.allowClear == "true") {
                        $("#" + self.options.id + "Id").val("");
                        $("#" + self.options.id + "Name").val("");
                    }
                    // 调用默认关闭事件，防止不回调
                    layer.close(index);
                },
                btn3: function (index) {
                    //按钮【关闭】的回调
                    layer.close(index);
                }
            });
        },

        /**
         * 展开树节点
         */
        expandNodes: function (nodes) {
            if (!nodes) return;
            for (var i = 0, l = nodes.length; i < l; i++) {
                // 表示展开节点
                // 只影响此节点，对于其 子孙节点无任何影响
                // 表示 展开 / 折叠 操作后，不设置任何焦点
                this.options.tree.expandNode(nodes[i], true, false, false);
                if (nodes[i].isParent && nodes[i].zAsync) {
                    this.expandNodes(nodes[i].children);
                }
            }
        },

        /**
         * 默认选择节点
         */
        selectCheckNode: function () {
            var ids = $("#" + this.options.id + "Id").val().split(",");
            for (var i = 0; i < ids.length; i++) {
                var node = this.options.tree.getNodeByParam("id", (this.options.attach == 'user' ? "u_" : '') + ids[i]);
                if (this.options.checked == true) {
                    try {
                        this.options.tree.checkNode(node, true, false);
                    } catch (e) {
                    }
                    this.options.tree.selectNode(node, false);
                } else {
                    this.options.tree.selectNode(node, true);
                }
            }
        },

        /**
         * 搜索节点
         */
        searchNode: function () {
            // 取得输入的关键字的值
            var value = $.trim(this.options.key.get(0).value);

            // 按名字查询
            var keyType = "name";

            // 如果和上次一次，就退出不查了。
            if (this.options.lastValue === value) {
                return;
            }

            // 保存最后一次
            this.options.lastValue = value;

            var nodes = this.options.tree.getNodes();
            // 如果要查空字串，就退出不查了。
            if (value == "") {
                this.showAllNode(nodes);
                return;
            }
            this.hideAllNode(nodes);
            var nodeList = this.options.tree.getNodesByParamFuzzy(keyType, value);
            this.updateNodes(nodeList);
        },

        /**
         * 隐藏所有节点
         */
        hideAllNode: function (nodes) {
            nodes = this.options.tree.transformToArray(nodes);
            for (var i = nodes.length - 1; i >= 0; i--) {
                this.options.tree.hideNode(nodes[i]);
            }
        },

        /**
         * 显示所有节点
         */
        showAllNode: function (nodes) {
            nodes = this.options.tree.transformToArray(nodes);
            for (var i = nodes.length - 1; i >= 0; i--) {
                /* if(!nodes[i].isParent){
                 tree.showNode(nodes[i]);
                 }else{ */
                if (nodes[i].getParentNode() != null) {
                    this.options.tree.expandNode(nodes[i], false, false, false, false);
                } else {
                    this.options.tree.expandNode(nodes[i], true, true, false, false);
                }
                this.options.tree.showNode(nodes[i]);
                this.showAllNode(nodes[i].children);
                /* } */
            }
        },

        /**
         * 更新节点状态
         */
        updateNodes: function (nodeList) {
            this.options.tree.showNodes(nodeList);
            for (var i = 0, l = nodeList.length; i < l; i++) {

                // 展开当前节点的父节点
                this.options.tree.showNode(nodeList[i].getParentNode());
                // tree.expandNode(nodeList[i].getParentNode(), true, false, false);
                // 显示展开符合条件节点的父节点
                while (nodeList[i].getParentNode() != null) {
                    this.options.tree.expandNode(nodeList[i].getParentNode(), true, false, false);
                    nodeList[i] = nodeList[i].getParentNode();
                    this.options.tree.showNode(nodeList[i].getParentNode());
                }
                // 显示根节点
                this.options.tree.showNode(nodeList[i].getParentNode());
                // 展开根节点
                this.options.tree.expandNode(nodeList[i].getParentNode(), true, false, false);
            }
        },

        // 开始搜索
        search: function () {
            $('#' + this.options.id + 'search').slideToggle(200);
            $('#' + this.options.id + 'txt').toggle();
            $('#' + this.options.id + 'key').focus();
        },

        /**
         * 构造树选择框
         */
        build: function (zNodes) {
            var self = this;
            // tree params
            // 复选框勾选类型
            var chkboxType = self.options.chkboxType;
            if (chkboxType == null || chkboxType == '') {
                chkboxType = {'Y': 'ps', 'N': 'ps'};
            }
            var setting = {
                view: {
                    selectedMulti: false, dblClickExpand: false,
                    nameIsHTML: true,
                    showIcon: false,
                    showTitle: false
                },
                // 设置 zTree 的节点上显示 checkbox / radio
                // chkStyle = "checkbox" 时，显示 checkbox 选择框，setting.check.chkboxType 属性有效。
                // chkStyle = "radio" 时，显示 radio 选择框， setting.check.radioType 属性有效。
                check: {
                    enable: self.options.checked, nocheckInherit: true, chkStyle: self.options.chkStyle,
                    radioType: "all", chkboxType: chkboxType
                },
                // {id, pId, name}
                data: {simpleData: {enable: true}},
                callback: {
                    onClick: function (event, treeId, treeNode) {
                        // 点击展开、折叠状态切换
                        tree.expandNode(treeNode);
                    }, onCheck: function (e, treeId, treeNode) { //
                        tree.expandNode(treeNode, true, false, false);
                        return false;
                    }, onAsyncSuccess: function (event, treeId, treeNode) {
                        var nodes = tree.getNodesByParam("pId", treeNode.id, null);
                        for (var i = 0, l = nodes.length; i < l; i++) {
                            try {
                                tree.checkNode(nodes[i], treeNode.checked, true);
                            } catch (e) {
                            }
                            //tree.selectNode(nodes[i], false);
                        }
                        self.selectCheckNode();
                    }, onDblClick: function () {
                        // 无选择框双击-->确定按钮
                        if (self.options.checked != true) {
                            var $layer = $("#" + self.options.id + "Tree").closest('.layui-layer');
                            $layer.find('.layui-layer-btn0').trigger("click");
                            // $("input[type='text']", top.mainFrame.document).focus();
                        }
                    }
                }
            };
            // 初始化树结构
            var tree = $.fn.zTree.init($("#" + self.options.id + "Tree"), setting, zNodes);
            self.options.tree = tree;

            // 默认展开一级节点
            var nodes = tree.getNodesByParam("level", 0);
            for (var i = 0; i < nodes.length; i++) {
                tree.expandNode(nodes[i], true, false, false);
            }

            self.selectCheckNode();
        },

        /**
         * 发送请求，取得表的数据
         * @params options 重新发送请求传递的参数
         */
        request: function (options) {
            var self = this;

            // 首先合并更新options
            if (options != null && typeof options == 'object') {
                if (typeof self.options == 'object') {
                    $.extend(true, self.options, options);
                }
            }

            // ajax添加
            var params = $.extend(true, {}, self.options.params);
            // 可以自己加入参数

            //发送Ajax请求
            $.ajax({
                url: self.options.dataurl,
                type: 'post',
                // json格式要求严格验证
                dataType: "json",
                data: params,
                success: function (result) {
                    self.options.datas = result;
                    self.build(result);
                },
                error: function (xhr, error) {
                    console.info('tree load data error.' + error);
                }
            });
        }
    };

    return TreeSelecter;
}))
;
